package com.butterknife.compiler;

import com.butterknife.annotations.BindView;
import com.google.auto.service.AutoService;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;

/*
 * create by LorenzoGao
 * Emial:2508719070@qq.com
 * DATE: 2019/4/19
 * TIME: 20:55
 * describe:
 */
@AutoService(Processor.class)
public class ButterknifeProcessor extends AbstractProcessor {


    private Filer mFiler;
    private Elements mElementUtils;


    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        mFiler = processingEnvironment.getFiler();
        mElementUtils = processingEnvironment.getElementUtils();
    }


    //指定版本
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();//获取最高版本
    }


    //需要处理的注解
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new LinkedHashSet<>();
        for (Class<? extends Annotation> annotation : getSupportedAnnotations()) {
            types.add(annotation.getCanonicalName());
        }
        return types;
    }


    /**
     * 有注解都会进来
     *
     * @param set
     * @param roundEnvironment
     * @return
     */
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {


        Set<? extends Element> element = roundEnvironment.getElementsAnnotatedWith(BindView.class);

        //解析属性 activity->List<Element>
        Map<Element, List<Element>> elementListMap = new HashMap<>();

        for (Element element1 : element) {
            Element enclosingElement = element1.getEnclosingElement();
            List<Element> viewBindElement = elementListMap.get(enclosingElement);
            if (viewBindElement == null) {
                viewBindElement = new ArrayList<>();
                elementListMap.put(enclosingElement, viewBindElement);
            }
            viewBindElement.add(element1);
        }

        //生成代码
        for (Map.Entry<Element, List<Element>> entry : elementListMap.entrySet()) {
            Element enclosingElement = entry.getKey();
            List<Element> viewBindElement = entry.getValue();

            //创建class
            String activityClassNameStr = enclosingElement.getSimpleName().toString();

            ClassName unbinderClassName = ClassName.get("com.butterknife", "Unbinder");//获取Unbinder的class名字
            ClassName activityClassName = ClassName.bestGuess(activityClassNameStr);
            TypeSpec.Builder classBuilder = TypeSpec.classBuilder(activityClassNameStr + "_ViewBinding");
            classBuilder.addModifiers(Modifier.FINAL, Modifier.PUBLIC)
                    .addSuperinterface(unbinderClassName)//添加修饰
                    .addField(activityClassName, "target", Modifier.PUBLIC);//添加属性


            //实现unbind方法
            ClassName callSuperClassName = ClassName.get("android.support.annotation", "CallSuper");//获取CallSuper注解
            MethodSpec.Builder unbindMethod = MethodSpec.methodBuilder("unbind")
                    .addAnnotation(Override.class)//添加属性
                    .addAnnotation(callSuperClassName)
                    .addModifiers(Modifier.PUBLIC);


            //构造函数
            MethodSpec.Builder constructorMethodBuilder = MethodSpec.constructorBuilder()
                    .addParameter(activityClassName, "target")
                    .addModifiers(Modifier.PUBLIC)
                    .addStatement("this.target=target");

// findViewById 属性
            for (Element element1 : viewBindElement) {
                String fieldName = element1.getSimpleName().toString();
                ClassName utilsClassName = ClassName.get("com.butterknife", "Utils");
                int resId = element1.getAnnotation(BindView.class).value();
                constructorMethodBuilder.addStatement("target.$L=$L.findViewById(target,$L)", fieldName, utilsClassName, resId);
                //target.text=null
                unbindMethod.addStatement("target.$L=null", fieldName);

            }


            classBuilder.addMethod(unbindMethod.build());
            classBuilder.addMethod(constructorMethodBuilder.build());


            //生成类
            try {
                String packName = mElementUtils.getPackageOf(enclosingElement).getQualifiedName().toString();//获取包名
                JavaFile.builder(packName, classBuilder.build())
                        .addFileComment("butterknife 自动生成")
                        .build().writeTo(mFiler);


            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("翻车了");
            }


        }

        return false;
    }


    /**
     * 添加需要解析的注解
     *
     * @return
     */
    private Set<Class<? extends Annotation>> getSupportedAnnotations() {
        Set<Class<? extends Annotation>> annotations = new LinkedHashSet<>();
        annotations.add(BindView.class);
        return annotations;
    }

}
